package com.yuan.socket.server;

import com.yuan.socket.data.DataService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
@EnableScheduling
@Slf4j
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
    //存放进入的人线程安全
    public static final ConcurrentHashMap<String, ChannelGroup> socket_group = new ConcurrentHashMap<>();

    private WebSocketServerHandshaker handshaker;
    DataService dataService;
    public WebSocketServerHandler(DataService dataServices) {
        dataService = dataServices;
    }
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
        log.info("msg类型 {}",msg);
        log.info("通道 {},地址:{}",channelHandlerContext.channel(),channelHandlerContext.channel().remoteAddress());
        if (msg instanceof FullHttpRequest) {
            handleHttpRequest(channelHandlerContext, (FullHttpRequest) msg);
        } else if (msg instanceof WebSocketFrame) {
            handleWebSocketFrame(channelHandlerContext, (WebSocketFrame) msg);
        }
    }
    /**
     * 1.请求是合法的 HTTP 格式。
     * 2.请求方法符合 WebSocket 协议要求。
     * 3.拦截非法请求，避免无效资源消耗
     */
    public void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
         System.out.println("http 握手操作");
         log.info("http解码结果 {}", req.decoderResult().isSuccess());
        //1. 检查 HTTP 解码结果
        if (!req.decoderResult().isSuccess()) {//decoderResult().isSuccess() 判断 HttpServerCodec 是否成功解析请求
            sendHttpResponse(ctx, req,
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }
        log.info("http请求方法 {} {}", req.method(),HttpMethod.GET);
        //2. 检查 HTTP 方法
        if (req.method() != HttpMethod.GET) {//WebSocket 握手必须使用 GET 方法 WebSocket 协议规定握手阶段必须通过 HTTP GET 请求触发（RFC 6455）
            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));

            return;
        }
        //添加更多安全校验（如 Origin 检查）
        // 3. 检查Upgrade头
        if (!req.headers().containsValue("Upgrade",  "websocket", true)) {
            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }
        System.out.println("握手操作检测完毕");
        log.info("握手开始 {} {},id:{}",req.headers().get(HttpHeaderNames.HOST),ctx.channel().id().asLongText(),ctx.channel().id());


        // 2. 构造握手响应
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                "ws://" + req.headers().get(HttpHeaderNames.HOST)  + "/ws", null, false);
        handshaker = wsFactory.newHandshaker(req);
        log.info("握手结果handshaker {}",handshaker);
        if ( handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
           handshaker.handshake(ctx.channel(),  req); // 完成握手 // 发送101 Switching Protocols
        }
//        if (handshaker.isHandshakeComplete())  {
//            logger.info("WebSocket 握手成功: {}", ctx.channel().id());
//        } else {
//            logger.warn(" 握手失败: {}", req.uri());
//        }
    }

    /**
     *优化建议
     * 1.添加响应头
     * 2.支持压缩：
     * 3.异步处理：
     */
    //res.headers().set(HttpHeaderNames.CONTENT_TYPE,  "text/plain; charset=UTF-8");
    //if (req.headers().contains(HttpHeaderNames.ACCEPT_ENCODING,  "gzip", true)) {
    // 使用Gzip压缩响应体
    //}
    //ChannelFuture f = ctx.writeAndFlush(res);
    //f.addListener(future  -> {
    //    if (!future.isSuccess())  {
    //        log.error(" 发送响应失败", future.cause());
    //    }
    //});
    public void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
        //1.判断http 响应是否是 200
        log.info("判断http响应 {} {}", res.status().code(),HttpResponseStatus.OK.code());
        if (res.status().code() != HttpResponseStatus.OK.code()) {
            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);//字符转化为字节缓冲区
            res.content().writeBytes(buf); // 将状态码描述写入响应体
            buf.release();
            res.headers().set(HttpHeaderNames.CONTENT_TYPE,  "text/plain; charset=UTF-8");
            HttpUtil.setContentLength(res, res.content().readableBytes());// 设置Content-Length头
        }
// 2. 发送响应
        log.info("发送响应: {}",res);
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        // 3. 决定是否关闭连接
        if (!HttpUtil.isKeepAlive(req) || res.status().code() != HttpResponseStatus.OK.code()) {//请求头中没有Connection: keep-alive
            f.addListener(ChannelFutureListener.CLOSE);// 响应完成后关闭连接
        }
    }
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
    public void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame req) {
        if(req instanceof CloseWebSocketFrame) {
            log.info("关闭连接: {}",ctx.channel());
            return;
        }
        if (req instanceof PingWebSocketFrame) {
            ctx.writeAndFlush(new  PongWebSocketFrame(req.content().retain()));
            return;
        }
//        if (req instanceof PongWebSocketFrame) {
//// 服务端主动发送 Ping
//            ctx.channel().writeAndFlush(new  PingWebSocketFrame(Unpooled.copiedBuffer("ping",  UTF_8)));
//        }

        if (req instanceof TextWebSocketFrame) {
            TextWebSocketFrame twsf = (TextWebSocketFrame) req; //通过获取消息的内容添加人员
            if(twsf.text().contains("socket")){
                String methodKey = "socket";//比如这是一个房间号
                ChannelGroup channelGroup = socket_group.get(methodKey);//询问老板这个房间我需要开会
                if (channelGroup ==null) {//老板说不好意思房间已经被别人用了没有了
                    channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);//默认开一个新的房间
                }
                channelGroup.add(ctx.channel());//当前这个人进入这个房间
                socket_group.put(methodKey, channelGroup);//把这个房间和人就开始运作了
                TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame("欢迎用户:"+ctx.channel().id());
                socket_group.get(methodKey).writeAndFlush(textWebSocketFrame);
            }
            log.info("websocket 消息: {}", ((TextWebSocketFrame) req).text());


//            TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame("链接进来了发送");
//            ctx.channel().writeAndFlush(textWebSocketFrame);
//            ctx.channel().writeAndFlush(req);
        }
    }
//    @Scheduled(fixedRate = 1000L)
//    public void sendAllMessageKline() {
//        System.out.println("sendAllMessageKline");
//
//        //log.info("时间戳 {}",System.currentTimeMillis());
//    }
}
